package heartbeat
import (
	"fmt"
	"time"

	"github.com/go-netty/go-netty"
	"github.com/go-netty/go-netty/codec/format"
	"github.com/go-netty/go-netty/codec/frame"
)

func main() {

	childInitializer := func(channel netty.Channel) {
		channel.Pipeline().
			AddLast(frame.DelimiterCodec(1024, "\n", true), format.TextCodec(), netty.ReadIdleHandler(time.Second), &ChildHandler{})
	}

	clientInitializer := func(channel netty.Channel) {
		channel.Pipeline().
			AddLast(frame.DelimiterCodec(1024, "\n", true), format.TextCodec(), netty.WriteIdleHandler(time.Second), &ClientHandler{})
	}

	bs := netty.NewBootstrap(netty.WithChildInitializer(childInitializer), netty.WithClientInitializer(clientInitializer))

	time.AfterFunc(time.Second, func() {

		channel, err := bs.Connect("127.0.0.1:9527", nil)
		if nil != err {
			panic(err)
		}

		channel.Write("Handshake")
	})

	bs.Listen(":9527").Sync()
}

type ChildHandler struct {
	LastReceivedTime time.Time
}

func (c *ChildHandler) HandleRead(ctx netty.InboundContext, message netty.Message) {
	fmt.Println("Server.HandleRead: ", message)
	c.LastReceivedTime = time.Now()
	ctx.HandleRead(message)
}

func (c *ChildHandler) HandleEvent(ctx netty.EventContext, event netty.Event) {

	switch event.(type) {
	case netty.ReadIdleEvent:
		if time.Since(c.LastReceivedTime) > time.Second * 3 {
			fmt.Println("Server.HandleEvent: check heartbeat timeout... close the server connection")
			ctx.Close(fmt.Errorf("check heartbeat failed"))
		}
	default:
		ctx.HandleEvent(event)
	}
}

type ClientHandler struct {
	SendHeartbeatNum int
}

func (c *ClientHandler) HandleActive(ctx netty.ActiveContext) {
	fmt.Println("Client.HandleActive: ", ctx.Channel().RemoteAddr())
	ctx.HandleActive()
}

func (c *ClientHandler) HandleInactive(ctx netty.InactiveContext, ex netty.Exception) {
	fmt.Println("Client.HandleInactive: ", ctx.Channel().RemoteAddr(), " ", ex)
	ctx.HandleInactive(ex)
}

func (c *ClientHandler) HandleRead(ctx netty.InboundContext, message netty.Message) {
	fmt.Println("Client.HandleRead: ", message)
	ctx.HandleRead(message)
}

func (c *ClientHandler) HandleEvent(ctx netty.EventContext, event netty.Event) {

	switch event.(type) {
	case netty.WriteIdleEvent:
		if c.SendHeartbeatNum < 5 {
			fmt.Println("Client.HandleEvent: ", "sending heartbeat message... ", c.SendHeartbeatNum)
			ctx.Write("Heartbeat")
			c.SendHeartbeatNum++
		}
	default:
		ctx.HandleEvent(event)
	}
}

